﻿using System;
using System.Collections.Generic;
using System.Text;

namespace PW.Mini.SlepowronskiJ.Siec.Algorytmy
{
    [Serializable]
    class AdaptacyjnyWspolczynnikUczeniaStrategiaSN : IStrategia
    {
        /// <summary>
        /// Learning decay rate.
        /// </summary>
        ///
        public const double LearningDecayDec = 0.7d;

        /// <summary>
        /// Learning decay rate.
        /// </summary>
        ///
        public const double LearningDecayInc = 1.05d;

        /// <summary>
        /// The maximum acceptable error increase
        /// </summary>
        ///
        public double MaxErrorInc = 1.02d;

        /// <summary>
        /// The current learning rate.
        /// </summary>
        ///
        private double _currentLearningRate = 0.0d;

        /// <summary>
        /// Max learning rate.
        /// </summary>
        ///
        private double maxLearningRate = 0.7d;

        /// <summary>
        /// Min learning rate.
        /// </summary>
        ///
        public const double minLearningRate = 0.000001d;

        /// <summary>
        /// The error rate from the previous iteration.
        /// </summary>
        ///
        private double _lastError;

        /// <summary>
        /// The error rate from the previous previous iteration.
        /// </summary>
        ///
        private double _preLastError;


        private void setLearningRate(double newLearningRate)
        {
            _currentLearningRate = Math.Max(minLearningRate, Math.Min(maxLearningRate, newLearningRate));
        }

        #region IStrategia Members


        public void PreInit(double learningRate)
        {
            setLearningRate(learningRate);
        }


        /// <summary>
        /// Initialize this strategy.
        /// </summary>
        ///
        /// <param name="train">The training algorithm.</param>
        public void Init(int size)
        {
            _preLastError = _lastError = -1;
            //maxLearningRate = Monitor.Instancja.WspolczynnikUczenia;
            maxLearningRate = 1.0d / size;
            setLearningRate(Monitor.Instancja.WspolczynnikUczenia);
            Monitor.Instancja.WspolczynnikUczenia = _currentLearningRate;
        }

        /// <summary>
        /// Called just after a training iteration.
        /// </summary>
        ///
        public void PostIteration()
        {
            if (_preLastError>0)
            {
                //if (Monitor.Instancja.BladSieci > _lastError && _lastError > _preLastError)
                if(Monitor.Instancja.BladSieci > MaxErrorInc * _lastError)
                {
                    setLearningRate(_currentLearningRate * LearningDecayDec);
                    Monitor.Instancja.WspolczynnikUczenia = _currentLearningRate;
                }
                else
                {
                    //zwiekszamy wspolczynnik uczenia tylko jak dwa razy z rzedu maleje blad
                    //if (Monitor.Instancja.BladSieci < _lastError && _lastError < _preLastError)
                    {
                        setLearningRate(_currentLearningRate * LearningDecayInc);
                        Monitor.Instancja.WspolczynnikUczenia = _currentLearningRate;
                    }
                }
            }
        }

        /// <summary>
        /// Called just before a training iteration.
        /// </summary>
        ///
        public void PreIteration()
        {
            _preLastError = _lastError;
            _lastError = Monitor.Instancja.BladSieci;
            //Monitor.Instancja.Logger.SendString(_currentLearningRate.ToString() + " error " + _lastError);
        }

        public bool ShouldStop()
        {
            return false;
        }

        #endregion
    }
}

